//FileName   : mangyun
//Author     : -
//Description: mangyun
//ModifyDate : 2019-5-8
//Company    : -
//Copy right : -
`include "define.v"


module mangyun (
    input               clk,
    input               rst_n,
    output              pmem_cs,
    output     [7:0]    pmem_adr,
    input     [7:0]     pmem_rdat,
    input               pmem_ack,
    output reg          dmem_cs,
    output reg          dmem_we,
    output reg [7:0]    dmem_adr,
    output     [7:0]    dmem_wdat,
    input     [7:0]     dmem_rdat,
    input               dmem_ack
);

//internal wire define
wire          rfr_wr;
wire [2:0]    rfr_wid;
wire [7:0]    rfr_wdat;
wire [7:0]    inst_rdat;
wire          pmem_we;
wire [7:0]    inst;
wire [7:0]    pc_next;
wire          de_inst_np;
wire          de_inst_p;
wire          de_inst_li_w;
wire          de_inst_push_w;
wire          de_inst_ex_w;
wire          de_inst_alu_w;
wire          de_inst_store_w;
wire          de_inst_load_w;
wire          de_inst_br_w;

//internal temp define
reg [7:0]     rfr0;
reg [7:0]     rfr1;
reg [7:0]     rfr2;
reg [7:0]     rfr3;
reg [7:0]     rfr4;
reg [7:0]     rfr5;
reg [7:0]     rfr6;
reg [7:0]     rfr7;
reg           reset;
reg [7:0]     pc_r;
reg [7:0]     stack_sec;
reg [2:0]     stack_pt;
reg           inst_np;
reg           inst_p;
reg [6:0]     de_imm0;
reg [6:0]     imm0;
reg           de_inst_li;
reg           inst_li;
reg           de_inst_push;
reg           inst_push;
reg [7:0]     stack_top;
reg           de_inst_ex;
reg           inst_ex;
reg           wb_inst_ex;
reg           de_inst_alu;
reg           inst_alu;
reg [4:0]     de_aluop;
reg [4:0]     aluop;
reg           de_inst_store;
reg           inst_store;
reg           de_inst_load;
reg           inst_load;
reg           wb_inst_load;
reg           de_inst_br;
reg           inst_br;
reg [7:0]     res;
reg [7:0]     src1_rfdat;
reg [7:0]     pc;



//---------------------------------------------
//Function: AA
//---------------------------------------------

assign rfr_wr = 1'b1;

assign rfr_wid = stack_pt;

assign rfr_wdat = stack_sec;

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr0 <= 8'd0;
    else begin
    if(rfr_wr&(rfr_wid==3'd0))
        rfr0 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr1 <= 8'd0;
    else begin
    if(rfr_wr&(rfr_wid==3'd1))
        rfr1 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr2 <= 8'd0;
    else begin
    if(rfr_wr&(rfr_wid==3'd2))
        rfr2 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr3 <= 8'd0;
    else begin
    if(rfr_wr&(rfr_wid==3'd3))
        rfr3 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr4 <= 8'd0;
    else begin
    if(rfr_wr&(rfr_wid==3'd4))
        rfr4 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr5 <= 8'd0;
    else begin
    if(rfr_wr&(rfr_wid==3'd5))
        rfr5 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr6 <= 8'd0;
    else begin
    if(rfr_wr&(rfr_wid==3'd6))
        rfr6 <= rfr_wdat;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rfr7 <= 8'd0;
    else begin
    if(rfr_wr&(rfr_wid==3'd7))
        rfr7 <= rfr_wdat;
    end
end


//dmem_cs
always @(*)
begin
    if(inst_store)
        dmem_cs = 1'b1;
    else if(inst_load)
        dmem_cs = 1'b1;
    else
        dmem_cs = 1'd0;
end


//dmem_we
always @(*)
begin
    if(inst_store)
        dmem_we = 1'b1;
    else if(inst_load)
        dmem_we = 1'b0;
    else
        dmem_we = 1'd0;
end


//dmem_adr
always @(*)
begin
    if(inst_store)
        dmem_adr = stack_sec;
    else if(inst_load)
        dmem_adr = stack_top;
    else
        dmem_adr = 8'd0;
end

assign dmem_wdat = stack_top;

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        reset <= {1'b1};
    else begin
    if(reset)
        reset <= 1'b0;
    end
end

assign pmem_cs = 1'b1;

assign inst_rdat = pmem_rdat;

assign pmem_we = 1'b0;

assign pmem_adr = pc[7:0];

assign inst = reset|inst_br|de_inst_load?`NOP:inst_rdat;

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        pc_r <= {`RSTPC};
    else begin
        pc_r <= pc;
    end
end

assign pc_next = pc_r+8'd1;


//pc
always @(*)
begin
    if(reset)
        pc = `RSTPC;
    else if(de_inst_load)
        pc = pc_r;
    else if(inst_br&stack_sec[0])
        pc = stack_top[7:0];
    else 
        pc = pc_next;
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        stack_sec <= 8'd0;
    else begin
    if(inst_p)
        stack_sec <= stack_top;
    else if(inst_np)
        stack_sec <= src1_rfdat;
    end
end


//src1_rfdat
always @(*)
begin
    case(stack_pt)
        3'd0:
            src1_rfdat = rfr0;
        3'd1:
            src1_rfdat = rfr1;
        3'd2:
            src1_rfdat = rfr2;
        3'd3:
            src1_rfdat = rfr3;
        3'd4:
            src1_rfdat = rfr4;
        3'd5:
            src1_rfdat = rfr5;
        3'd6:
            src1_rfdat = rfr6;
        3'd7:
            src1_rfdat = rfr7;
        default:
            src1_rfdat = 8'd0;
    endcase
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        stack_pt <= 3'd0;
    else begin
    if(inst_p&de_inst_p)
        stack_pt <= stack_pt+3'd1;
    else if(inst_np&de_inst_np)
        stack_pt <= stack_pt-3'd1;
    end
end

assign de_inst_np = inst_load|de_inst_alu|de_inst_store|de_inst_br;

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        inst_np <= 1'd0;
    else begin
        inst_np <= de_inst_np;
    end
end

assign de_inst_p = de_inst_li|de_inst_push;

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        inst_p <= 1'd0;
    else begin
        inst_p <= de_inst_p;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_imm0 <= 7'd0;
    else begin
        de_imm0 <= inst[`INST_IMM0];
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        imm0 <= 7'd0;
    else begin
        imm0 <= de_imm0;
    end
end

assign de_inst_li_w = inst[`INST_INST]==`INST_LI;

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_inst_li <= 1'd0;
    else begin
        de_inst_li <= de_inst_li_w;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        inst_li <= 1'd0;
    else begin
        inst_li <= de_inst_li;
    end
end

assign de_inst_push_w = (inst[`INST_INST]==`INST_EX)&(inst[`INST_OP]==`OP_PUSH);

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_inst_push <= 1'd0;
    else begin
        de_inst_push <= de_inst_push_w;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        inst_push <= 1'd0;
    else begin
        inst_push <= de_inst_push;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        stack_top <= 8'd0;
    else begin
    if(inst_li)
        stack_top <= imm0[6:0];
    else if(inst_alu)
        stack_top <= res;
    else if(inst_store)
        stack_top <= stack_sec;
    else if(wb_inst_load)
        stack_top <= dmem_rdat;
    else if(inst_br)
        stack_top <= stack_sec;
    end
end

assign de_inst_ex_w = inst[`INST_INST]==`INST_EX;

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_inst_ex <= 1'd0;
    else begin
        de_inst_ex <= de_inst_ex_w;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        inst_ex <= 1'd0;
    else begin
        inst_ex <= de_inst_ex;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        wb_inst_ex <= 1'd0;
    else begin
        wb_inst_ex <= inst_ex;
    end
end

assign de_inst_alu_w = (inst[`INST_INST]==`INST_EX)&inst[`INST_OP_4];

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_inst_alu <= 1'd0;
    else begin
        de_inst_alu <= de_inst_alu_w;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        inst_alu <= 1'd0;
    else begin
        inst_alu <= de_inst_alu;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_aluop <= 5'd0;
    else begin
    if((inst[`INST_INST]==`INST_EX)&inst[`INST_OP_4] )
        de_aluop <= inst[`INST_OP];
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        aluop <= 5'd0;
    else begin
        aluop <= de_aluop;
    end
end


//res
always @(*)
begin
    case(aluop[3:0])
        `ADD:
            res = stack_top + stack_sec;
        `SUB:
            res = stack_top - stack_sec;
        `AND:
            res = stack_top & stack_sec;
        `OR:
            res = stack_top | stack_sec;
        `XOR:
            res = stack_top ^ stack_sec;
        `LT:
            res = $signed(stack_top) < $signed(stack_sec);
        `LTU:
            res = stack_top < stack_sec;
        `GE:
            res = $signed(stack_top) >= $signed(stack_sec);
        `GEU:
            res = stack_top >= stack_sec;
        `EQ:
            res = stack_top == stack_sec;
        `NE:
            res = stack_top != stack_sec;
        `SLL:
            res = stack_top << stack_sec[4:0];
        `SRL:
            res = stack_top >> stack_sec[4:0];
        `SRA:
            res = $signed(stack_top) >>> stack_sec[4:0];
        `POP:
            res = stack_sec;
        default:
            res = 8'd0;
    endcase
end

assign de_inst_store_w = (inst[`INST_INST]==`INST_EX)&(inst[`INST_OP]==`OP_STORE);

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_inst_store <= 1'd0;
    else begin
        de_inst_store <= de_inst_store_w;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        inst_store <= 1'd0;
    else begin
        inst_store <= de_inst_store;
    end
end

assign de_inst_load_w = (inst[`INST_INST]==`INST_EX)&(inst[`INST_OP]==`OP_LOAD);

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_inst_load <= 1'd0;
    else begin
        de_inst_load <= de_inst_load_w;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        inst_load <= 1'd0;
    else begin
        inst_load <= de_inst_load;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        wb_inst_load <= 1'd0;
    else begin
        wb_inst_load <= inst_load;
    end
end

assign de_inst_br_w = (inst[`INST_INST]==`INST_EX)&(inst[`INST_OP]==`OP_BR);

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        de_inst_br <= 1'd0;
    else begin
        de_inst_br <= de_inst_br_w;
    end
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        inst_br <= 1'd0;
    else begin
        inst_br <= de_inst_br;
    end
end

endmodule
